/*
*
* 版权所有 Copyleft(c) 2005
* 刘炯个人工作室 Sharp-Mark Personal Studio
*
* 允许自由使用，复制，修改，传播和贩卖此源程序及其文档，而不必支付任何费用。
* 以上的版权信息必须出现在每一份复制品中。同时这份版权信息和许可声明
* 也必须出现在支持文档中。刘炯个人工作室不对此软件适于那种具体
* 用途做出任何阐述。此代码只作为代码本身提供对其品质不做任何保证。
*
*/

#include "stdafx.h"
#include "Hanoi.h"

Tower::Tower(){}

void Tower::PushOnePlate(Plate* plate)			// 移入一个块
{
	Plates.push_back(plate);
}

Plate* Tower::PopOnePlate()						// 移出一个块
{
	// 取得要移出的块
	vector<Plate*>::iterator p = Plates.end();
	Plate* plate = *(--p);
	Plates.pop_back();

	return plate;
}

void Hanoi::DrawTower(Tower& tower,	// 暂时没有用...
					  int x,		// 棍子底部的X坐标
					  int y)		// 棍子底部的Y坐标
{
		// 画棍
		_dc.MoveTo(x, y);
		_dc.LineTo(x, y - (this->_level + 1) * PLATE_HEIGHT);

		// 画底盘
		_dc.MoveTo(x - (this->_level + 1) * PLATE_WIDTH / 2, y);
		_dc.LineTo(x + (this->_level + 1) * PLATE_WIDTH / 2, y);

		// 画Plate
		int top, left;				// 要画的盘子的左上角坐标
		for (vector<Plate*>::iterator p = tower.Plates.begin(); p != tower.Plates.end(); p++)
		{
			left = x -(**p).Width() / 2;

			y -= (**p).Height();
			top = y;

			DrawPlate(**p, left, top);
		}
}

void Hanoi::DrawPlate(Plate& plate, int left, int top)
{
	CRect rect(left, top, left + plate.Width(), top + plate.Height());

	CBrush brush(plate.Color());
	CBrush *pOldBrush;

	pOldBrush = _dc.SelectObject(&brush);

	_dc.Rectangle(&rect);

	_dc.SelectObject(pOldBrush);

	//_dc.Rectangle(CRect(left, top, left + plate.Width(), top + plate.Height() ));
}

Hanoi::Hanoi(int level, CPaintDC& dc, CRect& clientRect)
			 : _level(level), _dc(dc), _rect(clientRect), _step(0)
{
	srand((unsigned)time(0));

	// 所有盘子的初始化
	_plates = new Plate[level];
	for(int i = 0; i < level; i++)
	{
		_plates[i] = Plate((i + 1) * PLATE_WIDTH, PLATE_HEIGHT, RGB(rand() % 255, rand() % 255, rand() % 255));
	}

	// 给柱子初始化
	if(level > 0)
	{
		do {
			_towers[0].PushOnePlate(&(_plates[--level]));
		}while(level > 0);
	}

	for(int i = 1; i < TOWER_NUMBER; i++)
	{
		_towers[i].Plates.clear();
	}
}

Hanoi::~Hanoi()
{
	delete [] _plates;
}

void Hanoi::MovePlates(Tower& Towersource, Tower& Towertransfer, Tower& Towerdestination, int level)
{
	// 递归...
	if(level > 1)
	{
		MovePlates(Towersource, Towerdestination, Towertransfer, level - 1);
		MovePlates(Towersource, Towertransfer, Towerdestination, 1);
		MovePlates(Towertransfer, Towersource, Towerdestination, level - 1);
	}
	else
	{
		// 移动，从source Tower到 destination Tower...
		Towerdestination.PushOnePlate( Towersource.PopOnePlate() );
		++_step;

		// 时间延时，以显示动画效果
		Sleep(500);

		// 画汉诺塔
		DrawHanoi();
	}
}

void Hanoi::Run()
{
	// 其他情况，不予以处理...
	if(_level < 1) return;

	// 初始调用，开始了
	MovePlates(_towers[0], _towers[1], _towers[2], _level);
}

void Hanoi::DrawHanoi()
{
	// 清空原来的图形
	_dc.FillRect(&_rect, &CBrush(RGB(255, 255, 255)));

	// 步骤显示
	CString text;
	text.Format("已经走的步数：%d", _step);
	_dc.TextOut(0, 0, text);

	// 块的位置
	int x, y;
	x = _rect.Width() / (TOWER_NUMBER + 1);
	y = _rect.Height() / 3 * 2;

	for (int i = 0; i < TOWER_NUMBER; i++)
	{
		DrawTower(_towers[i], x, y);
		// 计算下一个的位置
		x += _rect.Width() / (TOWER_NUMBER + 1);
	}
}